/*
	* Sketch1.ino
	*
	* Created: 9/25/2014 7:52:32 PM
	* Author: Mike
*/

#include <SPI.h>

const int slaveSelectPin = 10; // 11 - MOSI, 13 - SCK

byte leds[8];                  // display board

byte i,j;

volatile byte timer1_cnt;
unsigned int timer1_cnt_copy;
unsigned int timer1_high;
unsigned int timer1_low;
unsigned long rectime;

// array to save interrupt times
volatile byte avg_ready = 0;
volatile byte time_pointer=0;
unsigned long timesnap, lasttimesnap;
float time_array[16];  // volatile since changed by interupt routine

float rpm, rpm_avg;
unsigned long rpm_int;


// function to write to SPI connected display
void WriteDisplay(int address, int value)
{
	digitalWrite(slaveSelectPin,LOW);  // take the SS pin low to select the chip
	SPI.transfer(address);  //  send in the address and value via SPI:
	SPI.transfer(value);
	digitalWrite(slaveSelectPin,HIGH);   // take the SS pin high to de-select the chip:
}

// function to load display array onto leds
void LoadDisplay()
{
	for (int x=0;x<8;x++)
	{
		WriteDisplay(x+1,leds[x]);
	}
}

void rpm_fun()
{
	timesnap = millis();						// take time asap
	detachInterrupt(0);							// stop further interrupts

	if(timer1_cnt > 1) /// add a filter
	{
		//  stop timer1
		TCCR1B = 0;
		// preserve registers
		timer1_low=TCNT1L;
		timer1_high=TCNT1H;
		timer1_cnt_copy = timer1_cnt;
		// reset timer1
		TCNT1H=0;
		TCNT1L=8;	// compensate loop time
		timer1_cnt=0;
		// set timer1 going again
		TCCR1B = 2;

		// one shot calculations //
		/*
		rectime = timesnap - lasttimesnap;
		rpm = 60000/(float)rectime;
		lasttimesnap = timesnap;
		*/

		/*
		Serial.print(timer1_cnt_copy,DEC);
		Serial.print("\t");
		Serial.print(timer1_high,DEC);
		Serial.print("\t");
		Serial.print(timer1_low,DEC);
		Serial.print("\t");

		Serial.print(rectime,1);
		Serial.print("ms\t");
		Serial.print(rpm,1);
		Serial.print("\t");
		*/

			rectime = 65536*timer1_cnt_copy;
			rectime += 256*timer1_high;
			rectime += timer1_low;
			rpm = 120000000/(float)rectime;

		// send debug
		//Serial.print(rectime/2,1);
		//Serial.print("us\t");

		Serial.print(rpm,1);
		Serial.print("\t");

		// averaged calculations //
		time_array[time_pointer] = rpm;				// store current rpm
		time_pointer ++;							// increment the pointer
		if (time_pointer > 15)						// 16 records saved so flag it
		{
			avg_ready = 1;
		}
		time_pointer %= 16;							// modulus 16 to wrap the pointer

		if (digitalRead(3)) // if pin high show instant reading
		{
			rpm_int = rpm * 10;
			for (j=7;j>1;j--)
			{
				leds[j]=0x7F;		// blank digit
				if (rpm_int)
				{
					leds[j]=rpm_int%10;
					rpm_int /= 10;
				}
			}
			leds[6]=leds[6] | 0x80; // set dp
			leds[7]=0x7f; // bank 1/10ths to stop spurious accuracy
			Serial.println("0.0");
		}
		else
		{
			if (avg_ready)
			{
				rpm_avg = time_array[0];
				for (j=1;j<16;j++)
				{
					rpm_avg += time_array[j];
				}
				rpm_avg = rpm_avg/16;
				// do the display

				rpm_int = rpm_avg * 10;
				for (j=7;j>1;j--)
				{
					leds[j]=0x7F;		// blank digit
					if (rpm_int)
					{
						leds[j]=rpm_int%10;
						rpm_int /= 10;
					}
				}
				leds[6]=leds[6] | 0x80; // set dp
				// send debug
				Serial.println(rpm_avg,1);
			}

		}

	}
	delay(20);									// slug edge capture (2400rpm equates to 25ms)
	attachInterrupt(0, rpm_fun, FALLING);
}


// timer overflow interrupt called every 0.5*256*256us = 32ms
ISR(TIMER1_OVF_vect)
{
	// overflow flag is auto reset by vector
	timer1_cnt++;
	if (timer1_cnt >30)	// longer than 1 second blank the display
	{
		for (j=2;j<8;j++) // blank
		{
			leds[j]=10;
		}

		avg_ready = 0;
		time_pointer = 0;

		if (timer1_cnt>250)	// stop roll over
		{
			Serial.println("No signal");
			timer1_cnt=200;
		}
	}
}

void setup()
{
	Serial.begin(115200);	// Debugging only

	// set up timer1 (16bits) as a timer
	TCCR1A = 0; // simple timer
	TCCR1B = 2;	// set prescaler to 8 to give a 0.5uS increment
	TCCR1C = 0; // simple timer
	TIMSK1 = 1; // interrupt on overflow

	pinMode (slaveSelectPin, OUTPUT);	// set the slaveSelectPin as an output
	pinMode (3,INPUT_PULLUP);			// set display mode - leaving open give instant / grounding averaged

	SPI.begin(); 	// initialize SPI:

	// initialise the display
	WriteDisplay(0xFF,0x01);  // display test
	delay(300);
	Serial.println("Software Rev_8 (8th October 2014)");
	WriteDisplay(0xFF,0x00);  // display test off
	WriteDisplay(0x0C,0x01);  // set normal operation
	WriteDisplay(0x0A,0x06);  // quarter brightness
	WriteDisplay(0x0B,0x07);  // scan all eight digits
	WriteDisplay(0x09,0xFC);  // set matrix 2-7 as char decode, 0 and 1 as binary
/*
	for (i=0;i<8;i++) // load display
	{
		leds[i]=i;
	}
*/
	LoadDisplay();
	delay(500);

	for (i=2;i<8;i++) // load display
	{
		leds[i]=0x7F;
	}
	leds[0]=2;
	leds[1]=0;

	LoadDisplay();
	//Interrupt 0 is digital pin 2, so that is where the IR detector is connected
	//Triggers on FALLING (change from HIGH to LOW)
	attachInterrupt(0, rpm_fun, FALLING);
}

void loop()
{
	leds[0]=leds[0] ^ 2; // toggle confidence LED

	LoadDisplay();

	delay(500);
}




